"""
活动调度模块 - 负责根据时间段和老人需求安排合适的活动

该模块实现了基于时间的活动优先级排序和分配，确保：
1. 基本生理需求（睡眠、用餐等）在合适的时间段得到满足
2. 医疗和护理活动在合适的时间段进行
3. 活动安排符合老年人的生活规律和习惯
"""

import logging


class ActivityScheduler:
    """活动调度器 - 负责根据时间段和老人需求安排合适的活动"""

    # 定义时间段常量
    EARLY_MORNING = "early_morning"  # 凌晨 (00:00-06:00)
    MORNING = "morning"  # 早晨 (06:00-09:00)
    FORENOON = "forenoon"  # 上午 (09:00-12:00)
    NOON = "noon"  # 中午 (12:00-14:00)
    AFTERNOON = "afternoon"  # 下午 (14:00-17:00)
    EVENING = "evening"  # 傍晚 (17:00-20:00)
    NIGHT = "night"  # 晚上 (20:00-22:00)
    LATE_NIGHT = "late_night"  # 深夜 (22:00-24:00)

    # 定义活动类型常量
    SLEEP = "sleep"  # 睡眠活动
    MEAL = "meal"  # 用餐活动
    MEDICAL = "medical"  # 医疗活动
    HYGIENE = "hygiene"  # 卫生活动
    REHABILITATION = "rehabilitation"  # 康复活动
    SOCIAL = "social"  # 社交活动
    ENTERTAINMENT = "entertainment"  # 娱乐活动

    def __init__(self, logger=None):
        """初始化活动调度器

        Args:
            logger: 日志记录器，如果为None则创建新的日志记录器
        """
        self.logger = logger or logging.getLogger(__name__)

        # 初始化时间段映射
        self.time_period_map = {
            (0, 6): self.EARLY_MORNING,  # 凌晨 (00:00-06:00)
            (6, 9): self.MORNING,  # 早晨 (06:00-09:00)
            (9, 12): self.FORENOON,  # 上午 (09:00-12:00)
            (12, 14): self.NOON,  # 中午 (12:00-14:00)
            (14, 17): self.AFTERNOON,  # 下午 (14:00-17:00)
            (17, 20): self.EVENING,  # 傍晚 (17:00-20:00)
            (20, 22): self.NIGHT,  # 晚上 (20:00-22:00)
            (22, 24): self.LATE_NIGHT,  # 深夜 (22:00-24:00)
        }

        # 初始化活动类型映射
        self.activity_type_map = {
            # 睡眠活动
            10: self.SLEEP,  # 睡眠
            # 用餐活动
            8: self.MEAL,  # 饮食
            64: self.MEAL,  # 协助老年人进食
            65: self.MEAL,  # 协助老年人饮水
            66: self.MEAL,  # 协助老年人鼻饲
            67: self.MEAL,  # 协助老年人胃造瘘管饲
            68: self.MEAL,  # 协助老年人空肠造瘘管饲
            69: self.MEAL,  # 救助噎食、误吸的老年人
            70: self.MEAL,  # 协助老年人进食训练
            71: self.MEAL,  # 协助老年人饮水训练
            72: self.MEAL,  # 协助老年人鼻饲训练
            73: self.MEAL,  # 协助老年人胃造瘘管饲训练
            # 卫生活动
            74: self.HYGIENE,  # 帮助老年人如厕
            76: self.HYGIENE,  # 协助老年人使用便器
            77: self.HYGIENE,  # 协助老年人使用尿壶
            82: self.HYGIENE,  # 协助老年人更换尿不湿
            83: self.HYGIENE,  # 协助老年人清洁会阴部
            95: self.HYGIENE,  # 协助老年人洗头
            97: self.HYGIENE,  # 协助老年人更换开襟衣服
            98: self.HYGIENE,  # 协助老年人更换套头衣服
            100: self.HYGIENE,  # 协助老年人更换裤子
            101: self.HYGIENE,  # 协助老年人刷牙
            106: self.HYGIENE,  # 协助老年人洗脸
            108: self.HYGIENE,  # 协助老年人洗手
            111: self.HYGIENE,  # 协助老年人洗澡
            112: self.HYGIENE,  # 协助老年人淋浴
            113: self.HYGIENE,  # 协助老年人盆浴
            114: self.HYGIENE,  # 协助老年人床上擦浴
            # 医疗活动
            85: self.MEDICAL,  # 为有肠造瘘的老年人更换粪袋
            86: self.MEDICAL,  # 为老年人测量体温
            87: self.MEDICAL,  # 为老年人测量脉搏
            88: self.MEDICAL,  # 为老年人测量呼吸
            89: self.MEDICAL,  # 为老年人测量血压
            90: self.MEDICAL,  # 为老年人测量血糖
            # 康复活动
            154: self.REHABILITATION,  # 教老年人使用健身器材
            155: self.REHABILITATION,  # 帮助老年人从仰卧位至侧卧位的体位转换
            156: self.REHABILITATION,  # 帮助老年人从仰卧位至坐位的体位转换
            157: self.REHABILITATION,  # 帮助老年人从仰卧位至床边坐起的体位转换
            158: self.REHABILITATION,  # 辅导老年人完成健身康复操
            159: self.REHABILITATION,  # 带领智力障碍老年人进行康复训练
            160: self.REHABILITATION,  # 教老年人使用拐杖进行活动
            161: self.REHABILITATION,  # 教老年人使用轮椅进行活动
            162: self.REHABILITATION,  # 使用平车转运老年人
            163: self.REHABILITATION,  # 帮助老年人进行穿脱衣服训练
            164: self.REHABILITATION,  # 帮助老年人进行站立、行走等活动
            165: self.REHABILITATION,  # 帮助肢体障碍老年人进行功能训练
            166: self.REHABILITATION,  # 帮助压力性尿失禁老年人进行功能训练
            # 社交活动
            167: self.SOCIAL,  # 指定老年人个体心理辅导方案
            168: self.SOCIAL,  # 指定老年人团体心理辅导方案
            169: self.SOCIAL,  # 用讲解法为老年人讲解心理健康知识
            170: self.SOCIAL,  # 用讨论法为老年人讲解心理健康知识
            171: self.SOCIAL,  # 用角色扮演法为老年人讲解心理健康知识
            172: self.SOCIAL,  # 识别老年人的抑郁情绪及其原因
            173: self.SOCIAL,  # 识别老年痴呆症
            174: self.SOCIAL,  # 用语言和肢体语言疏导老年人不良情绪
            175: self.SOCIAL,  # 合理情绪法
        }

        # 定义时间段活动优先级
        # 格式: {时间段: {活动类型: 优先级}}，优先级越高越优先安排
        self.time_activity_priority = {
            self.EARLY_MORNING: {
                self.SLEEP: 100,  # 凌晨优先安排睡眠
                self.MEDICAL: 50,  # 紧急医疗需求次之
                self.HYGIENE: 10,  # 紧急卫生需求
                self.MEAL: 5,  # 特殊情况下的用餐
                self.REHABILITATION: 1,
                self.SOCIAL: 1,
                self.ENTERTAINMENT: 1,
            },
            self.MORNING: {
                self.HYGIENE: 90,  # 早晨优先安排洗漱、如厕等
                self.MEAL: 80,  # 早餐
                self.MEDICAL: 70,  # 晨间医疗检查
                self.SLEEP: 20,  # 部分老人可能仍在睡眠
                self.REHABILITATION: 40,
                self.SOCIAL: 30,
                self.ENTERTAINMENT: 10,
            },
            self.FORENOON: {
                self.REHABILITATION: 90,  # 上午优先安排康复训练
                self.MEDICAL: 80,  # 医疗活动
                self.HYGIENE: 70,  # 卫生活动
                self.SOCIAL: 60,  # 社交活动
                self.ENTERTAINMENT: 50,  # 娱乐活动
                self.MEAL: 30,  # 加餐
                self.SLEEP: 10,  # 短暂休息
            },
            self.NOON: {
                self.MEAL: 100,  # 中午优先安排午餐
                self.HYGIENE: 70,  # 餐后卫生
                self.SLEEP: 60,  # 午休
                self.MEDICAL: 50,  # 必要的医疗活动
                self.REHABILITATION: 20,
                self.SOCIAL: 10,
                self.ENTERTAINMENT: 10,
            },
            self.AFTERNOON: {
                self.REHABILITATION: 90,  # 下午优先安排康复训练
                self.SOCIAL: 80,  # 社交活动
                self.ENTERTAINMENT: 70,  # 娱乐活动
                self.MEDICAL: 60,  # 医疗活动
                self.HYGIENE: 50,  # 卫生活动
                self.MEAL: 30,  # 加餐
                self.SLEEP: 10,  # 短暂休息
            },
            self.EVENING: {
                self.MEAL: 100,  # 晚餐
                self.HYGIENE: 80,  # 餐后卫生
                self.SOCIAL: 70,  # 社交活动
                self.ENTERTAINMENT: 60,  # 娱乐活动
                self.MEDICAL: 50,  # 医疗活动
                self.REHABILITATION: 30,  # 轻度康复活动
                self.SLEEP: 10,  # 短暂休息
            },
            self.NIGHT: {
                self.HYGIENE: 90,  # 睡前洗漱、如厕等
                self.SOCIAL: 70,  # 睡前社交
                self.ENTERTAINMENT: 60,  # 睡前娱乐
                self.MEDICAL: 50,  # 睡前医疗检查
                self.MEAL: 30,  # 睡前加餐
                self.SLEEP: 20,  # 部分老人可能已开始睡眠
                self.REHABILITATION: 10,  # 轻度康复活动
            },
            self.LATE_NIGHT: {
                self.SLEEP: 100,  # 深夜优先安排睡眠
                self.MEDICAL: 50,  # 紧急医疗需求
                self.HYGIENE: 30,  # 紧急卫生需求
                self.MEAL: 10,  # 特殊情况下的用餐
                self.REHABILITATION: 1,
                self.SOCIAL: 1,
                self.ENTERTAINMENT: 1,
            },
        }

        # 定义固定时间活动
        # 格式: {(开始小时, 结束小时): [(活动类型, 活动ID)]}
        self.fixed_time_activities = {
            # 睡眠时间 (22:00-06:00)
            (22, 6): [(self.SLEEP, 10)],
            # 早餐时间 (07:00-08:30)
            (7, 8.5): [(self.MEAL, 8), (self.MEAL, 64), (self.MEAL, 65)],
            # 午餐时间 (11:30-13:00)
            (11.5, 13): [(self.MEAL, 8), (self.MEAL, 64), (self.MEAL, 65)],
            # 晚餐时间 (17:30-19:00)
            (17.5, 19): [(self.MEAL, 8), (self.MEAL, 64), (self.MEAL, 65)],
        }

        # 定义不适合在特定时间段进行的活动
        # 格式: {时间段: [活动ID列表]}
        self.unsuitable_activities = {
            self.EARLY_MORNING: [
                # 凌晨时段禁止所有非睡眠活动
                # 将所有非睡眠活动ID都加入列表
                8,
                64,
                65,
                66,
                67,
                68,
                69,
                70,
                71,
                72,
                73,  # 用餐活动
                74,
                76,
                77,
                82,
                83,
                95,
                97,
                98,
                100,
                101,
                106,
                108,
                111,
                112,
                113,
                114,  # 卫生活动
                85,
                86,
                87,
                88,
                89,
                90,  # 医疗活动
                154,
                155,
                156,
                157,
                158,
                159,
                160,
                161,
                162,
                163,
                164,
                165,
                166,  # 康复训练
                167,
                168,
                169,
                170,
                171,
                172,
                173,
                174,
                175,  # 社交活动
            ],
            self.LATE_NIGHT: [
                # 深夜时段禁止所有非睡眠活动
                # 将所有非睡眠活动ID都加入列表
                8,
                64,
                65,
                66,
                67,
                68,
                69,
                70,
                71,
                72,
                73,  # 用餐活动
                74,
                76,
                77,
                82,
                83,
                95,
                97,
                98,
                100,
                101,
                106,
                108,
                111,
                112,
                113,
                114,  # 卫生活动
                85,
                86,
                87,
                88,
                89,
                90,  # 医疗活动
                154,
                155,
                156,
                157,
                158,
                159,
                160,
                161,
                162,
                163,
                164,
                165,
                166,  # 康复训练
                167,
                168,
                169,
                170,
                171,
                172,
                173,
                174,
                175,  # 社交活动
            ],
        }

    def get_time_period(self, time_str):
        """根据时间字符串获取对应的时间段

        Args:
            time_str: 时间字符串，格式为"HH:MM-HH:MM"或"HH:MM"

        Returns:
            时间段常量
        """
        # 解析时间字符串
        if "-" in time_str:
            # 如果是时间段格式，取开始时间
            start_time = time_str.split("-")[0]
        else:
            # 如果只是时间点
            start_time = time_str

        # 解析小时和分钟
        hour, minute = map(int, start_time.split(":"))

        # 转换为小时数（带小数）
        hour_decimal = hour + minute / 60

        # 查找对应的时间段
        for (start, end), period in self.time_period_map.items():
            # 处理跨天的情况
            if start < end:  # 不跨天
                if start <= hour_decimal < end:
                    return period
            else:  # 跨天
                if hour_decimal >= start or hour_decimal < end:
                    return period

        # 默认返回早晨时间段
        self.logger.warning(f"无法确定时间 {time_str} 的时间段，默认返回早晨时间段")
        return self.MORNING

    def get_activity_type(self, activity_id):
        """根据活动ID获取活动类型

        Args:
            activity_id: 活动ID

        Returns:
            活动类型常量
        """
        # 尝试将活动ID转换为整数
        try:
            activity_id = int(activity_id)
        except (ValueError, TypeError):
            self.logger.warning(f"无效的活动ID: {activity_id}，无法确定活动类型")
            return None

        # 查找对应的活动类型
        return self.activity_type_map.get(activity_id)

    def get_activity_priority(self, activity_id, time_str):
        """获取活动在指定时间段的优先级

        Args:
            activity_id: 活动ID
            time_str: 时间字符串，格式为"HH:MM-HH:MM"或"HH:MM"

        Returns:
            优先级分数，分数越高优先级越高
        """
        # 获取时间段
        time_period = self.get_time_period(time_str)

        # 获取活动类型
        activity_type = self.get_activity_type(activity_id)

        # 如果无法确定活动类型，返回默认优先级
        if activity_type is None:
            return 0

        # 检查是否是不适合在该时间段进行的活动
        if (
            time_period in self.unsuitable_activities
            and int(activity_id) in self.unsuitable_activities[time_period]
        ):
            return -100  # 给予极低的优先级

        # 获取该时间段该活动类型的优先级
        return self.time_activity_priority.get(time_period, {}).get(activity_type, 0)

    def is_fixed_time_activity(self, activity_id, time_str):
        """检查活动是否是固定时间活动

        Args:
            activity_id: 活动ID
            time_str: 时间字符串，格式为"HH:MM-HH:MM"或"HH:MM"

        Returns:
            布尔值，表示是否是固定时间活动
        """
        # 解析时间字符串
        if "-" in time_str:
            # 如果是时间段格式，取开始时间
            start_time = time_str.split("-")[0]
        else:
            # 如果只是时间点
            start_time = time_str

        # 解析小时和分钟
        hour, minute = map(int, start_time.split(":"))

        # 转换为小时数（带小数）
        hour_decimal = hour + minute / 60

        # 获取活动类型
        activity_type = self.get_activity_type(activity_id)

        # 如果无法确定活动类型，返回False
        if activity_type is None:
            return False

        # 检查是否是固定时间活动
        for (start, end), activities in self.fixed_time_activities.items():
            # 检查时间是否在范围内
            is_time_in_range = False
            if start < end:  # 不跨天
                is_time_in_range = start <= hour_decimal < end
            else:  # 跨天
                is_time_in_range = hour_decimal >= start or hour_decimal < end

            # 如果时间在范围内，检查活动是否匹配
            if is_time_in_range:
                for act_type, act_id in activities:
                    if act_type == activity_type and int(activity_id) == act_id:
                        return True

        return False

    def sort_activities_by_priority(self, activities, time_str):
        """根据优先级对活动进行排序

        Args:
            activities: 活动ID列表
            time_str: 时间字符串，格式为"HH:MM-HH:MM"或"HH:MM"

        Returns:
            排序后的活动ID列表，优先级高的在前
        """
        # 计算每个活动的优先级
        activity_priorities = []
        for activity_id in activities:
            priority = self.get_activity_priority(activity_id, time_str)
            is_fixed = self.is_fixed_time_activity(activity_id, time_str)

            # 固定时间活动优先级最高
            if is_fixed:
                priority += 1000

            activity_priorities.append((activity_id, priority))

        # 根据优先级排序
        activity_priorities.sort(key=lambda x: x[1], reverse=True)

        # 返回排序后的活动ID列表
        return [activity_id for activity_id, _ in activity_priorities]

    def get_suitable_activity(self, activities, time_str, care_level=None):
        """获取适合在指定时间段进行的活动

        Args:
            activities: 活动ID列表
            time_str: 时间字符串，格式为"HH:MM-HH:MM"或"HH:MM"
            care_level: 照护需求级别（1-3），如果为None则不考虑照护需求级别

        Returns:
            最适合的活动ID，如果没有适合的活动则返回None
        """
        # 如果活动列表为空，返回None
        if not activities:
            return None

        # 获取时间段
        time_period = self.get_time_period(time_str)

        # 解析时间字符串
        if "-" in time_str:
            # 如果是时间段格式，取开始时间
            start_time = time_str.split("-")[0]
        else:
            # 如果只是时间点
            start_time = time_str

        # 解析小时和分钟
        hour, minute = map(int, start_time.split(":"))

        # 转换为小时数（带小数）
        hour_decimal = hour + minute / 60

        # 特殊处理：凌晨和深夜时间段只安排睡眠活动
        if time_period in [self.EARLY_MORNING, self.LATE_NIGHT]:
            # 查找睡眠活动
            for activity_id in activities:
                if int(activity_id) == 10:  # 睡眠活动ID为10
                    return activity_id

            # 如果没有睡眠活动，返回None
            self.logger.warning(f"在{time_period}时间段没有找到睡眠活动，返回None")
            return None

        # 检查是否是睡眠时间
        is_sleep_time = False
        for (start, end), act_list in self.fixed_time_activities.items():
            if any(act_type == self.SLEEP for act_type, _ in act_list):
                # 检查时间是否在范围内
                if start < end:  # 不跨天
                    if start <= hour_decimal < end:
                        is_sleep_time = True
                        break
                else:  # 跨天
                    if hour_decimal >= start or hour_decimal < end:
                        is_sleep_time = True
                        break

        # 如果是睡眠时间，优先安排睡眠活动
        if is_sleep_time:
            # 查找睡眠活动
            for activity_id in activities:
                if self.get_activity_type(activity_id) == self.SLEEP:
                    return activity_id

        # 检查是否是用餐时间
        is_meal_time = False
        for (start, end), act_list in self.fixed_time_activities.items():
            if any(act_type == self.MEAL for act_type, _ in act_list):
                # 检查时间是否在范围内
                if start < end:  # 不跨天
                    if start <= hour_decimal < end:
                        is_meal_time = True
                        break
                else:  # 跨天
                    if hour_decimal >= start or hour_decimal < end:
                        is_meal_time = True
                        break

        # 如果是用餐时间，优先安排用餐活动
        if is_meal_time:
            # 查找用餐活动
            for activity_id in activities:
                if self.get_activity_type(activity_id) == self.MEAL:
                    return activity_id

        # 根据优先级排序活动
        sorted_activities = self.sort_activities_by_priority(activities, time_str)

        # 如果有照护需求级别，根据级别调整活动选择
        if care_level is not None:
            # 高级别照护需求优先选择医疗和康复活动
            if care_level == 3:
                for activity_id in sorted_activities:
                    activity_type = self.get_activity_type(activity_id)
                    if activity_type in [self.MEDICAL, self.REHABILITATION]:
                        return activity_id

            # 中级别照护需求优先选择卫生和社交活动
            elif care_level == 2:
                for activity_id in sorted_activities:
                    activity_type = self.get_activity_type(activity_id)
                    if activity_type in [self.HYGIENE, self.SOCIAL]:
                        return activity_id

            # 低级别照护需求优先选择娱乐活动
            elif care_level == 1:
                for activity_id in sorted_activities:
                    activity_type = self.get_activity_type(activity_id)
                    if activity_type in [self.ENTERTAINMENT, self.SOCIAL]:
                        return activity_id

        # 如果没有根据照护需求级别找到合适的活动，返回优先级最高的活动
        if sorted_activities:
            return sorted_activities[0]

        # 如果没有合适的活动，返回None
        return None
